import Raphael from 'Raphael';

import {
    RectNode
} from './modules/rect';
import {
    PathNode
} from './modules/path';
import {
    Tools
} from './modules/tools';

import _ from 'lodash';

class SevenFlow {

    constructor() {
        this.rapheal = Raphael;
        this.elements = {
            nodes: [],
            paths: []
        };
        this.activeElem = null;
        this.tempPath = null;
        this.event = {};
        this.mode = 1; // 1:普通,2:连线
        this.rectPos = {
            x: 100,
            y: 50
        };
        this.options = {
            page: {
                width: 800,
                height: 600
            },
            node: {
                width: 120,
                height: 60,
                onConnect: (node) => {
                    console.log('connect', node);
                },
                onSetting: (node) => {
                    console.log('setting', node);
                },
                onClose: (node) => {
                    console.log('close', node);
                }
            },
            path: {
                stroke: '#888888',
                onSetting: (path) => {
                    console.log('setting', path);
                }
            },
            tools: {
                title: '工具栏',
                saveButtonText: '确定',
                saveFn: (e) => console.log('点击了保存按钮', e),
                item: [
                    {
                        name: '开始',
                        type: 'start'
                    },
                    {
                        name: '节点',
                        type: 'node'
                    },
                    {
                        name: '结束',
                        type: 'end'
                    }
                ]
            },
            imgPath: './assets/images/',
            editable: true
        };
    }

    init(dom, options) {
        this.dom = dom;
        _.merge(this.options, options);
        this.pager = this.rapheal(dom, this.options.page.width, this.options.page.height);
        this.options.editable && this.initTools();
    }

    initTools() {
        let tools = new Tools(this, this.options.tools);
        document.getElementById(this.dom).appendChild(tools.getHtmlElement());
    }

    rect(options) {
        if (!options.x) {
            _.merge(options, {
                x: sf.rectPos.x,
                y: sf.rectPos.y,
                width: sf.options.node.width,
                height: sf.options.node.height,
            });
            sf.rectPos.x += 10;
            sf.rectPos.y += 10;
            if (sf.rectPos.x >= sf.options.page.width || sf.rectPos.y >= sf.options.page.height) {
                sf.rectPos.x = 100;
                sf.rectPos.y = 50;
            }
        }
        const rect = new RectNode(this, options);
        this.elements.nodes.push(rect);
        return rect;
    }

    connect(from, e1) {
        sf.mode = 2;
        let f = {
            x: from[2].attr('x'),
            y: from[2].attr('y')
        };
        let to = {
            x: e1.offsetX,
            y: e1.offsetY
        };
        this.tempPath = sf.pager.path(`M${f.x} ${f.y}L${to.x} ${to.y}`).attr('stroke', this.options.path.stroke);
        sf.pager.canvas.onmousemove = (e) => {
            sf.pager.canvas.style.cursor = 'crosshair';
            let temp = {
                x: e.offsetX - 5,
                y: e.offsetY - 5
            };
            this.tempPath.attr('path', `M${f.x} ${f.y}L${temp.x} ${temp.y}`);
            sf.pager.canvas.onclick = (e1) => {
                sf.mode = 1;
                sf.pager.canvas.style.cursor = 'default';
                sf.pager.canvas.onmousemove = null;
                sf.pager.canvas.onclick = null;
                this.tempPath.remove();
            }
        };

    }

    path(from, to, attr) {
        if (to.type === 'start') {
            return console.warn('Cannot connect to start node!');
        }
        let exist = false,
            reverse = false;
        for (let i = 0; i < this.elements.paths.length; i++) {
            if ((this.elements.paths[i].from.id === from.id && this.elements.paths[i].to.id === to.id) || (this.elements.paths[i].to.id === from.id && this.elements.paths[i].from.id === to.id)) {
                exist = true;
            }
        }
        if (exist) {
            return console.warn('Path have been exist!');
        }
        const path = new PathNode(this, from, to, attr);
        this.elements.paths.push(path);
        return path;
    }

    getActiveElem() {
        return this.activeElem;
    }

    addEvent(event, handler) {
        if (!this.event) {
            this.event = {}
        }
        if (!this.event[event]) {
            this.event[event] = []
        }
        this.event[event].push(handler);
    }

    trigger(event) {
        if (this.event[event]) {
            for (let i = 0; i < this.event[event].length; i++) {
                this.event[event][i](...[].slice.call(arguments, 1))
            }
        }
    }

    removeEvent(event) {
        if (this.event[event]) {
            delete this.event[event]
        }
    }

    removeNode(id) {
        let removeIndex = -1;
        for (let i = 0; i < this.elements.nodes.length; i++) {
            if (id === this.elements.nodes[i].id) {
                removeIndex = i;
            }
        }
        if (removeIndex !== -1) {
            this.elements.nodes.splice(removeIndex, 1);
        }
    }

    removePath(id) {
        let removeIndex = -1;
        for (let i = 0; i < this.elements.paths.length; i++) {
            if (id === this.elements.paths[i].id) {
                removeIndex = i;
            }
        }
        if (removeIndex !== -1) {
            this.elements.paths.splice(removeIndex, 1);
        }
    }

    getJsonObject() {
        let obj = {
            nodes: [],
            paths: []
        }
        for (let i = 0; i < this.elements.nodes.length; i++) {
            obj.nodes.push(this.elements.nodes[i].getNode());
        }
        for (let i = 0; i < this.elements.paths.length; i++) {
            obj.paths.push(this.elements.paths[i].getPath());
        }
        return obj;
    }

    recover(data) {
        if (data.nodes) {
            data.nodes.forEach(node => {
                this.rect(node);
            });
            if (data.paths) {
                data.paths.forEach(path => {
                    let from, to;
                    const fs = _.filter(this.elements.nodes, {id: path.from});
                    if (fs.length > 0) {
                        from = fs[0];
                    }
                    const ts = _.filter(this.elements.nodes, {id: path.to});
                    if (ts.length > 0) {
                        to = ts[0];
                    }
                    const attr = {
                        name: path.name,
                        reverse: path.reverse || '0',
                        lineType: path.lineType || 'solid'
                    };
                    this.path(from, to, attr);
                });
            }
        }
    }
}

export {
    SevenFlow
}